import importlib
from . import config
from . import errcode
from . import logger
from . import user
from .connection import Connection
from .errcode import ImError

__all__ = ["AuthFailedErr", "authenticate", "login_required", "login", "logout", "is_logged_in"]

logger = logger.get_logger(__package__)


class AuthFailedErr(BaseException):
    pass


_auth_funcs = []
_online_users = {}

for auth_module in config.auth_modules:
    module = importlib.import_module(auth_module)
    if not hasattr(module, "authenticate"):
        raise Exception("No authenticate function found in module " + auth_module)
    _auth_funcs.append(getattr(module, "authenticate"))
    logger.info("Loaded authentication module [%s]" % auth_module)


def authenticate(username, password):
    for func in _auth_funcs:
        u = func(username, password)
        if user and isinstance(u, user.User):
            u.authenticated = True
            return u

    raise AuthFailedErr


def login(connection, u):
    assert isinstance(connection, Connection)
    assert isinstance(u, user.User)
    setattr(u, "connection", connection)
    setattr(connection, "user", u)
    logger.info("%s is logging on" % id(connection.user))


def is_logged_in(connection):
    return hasattr(connection, "user")


def logout(connection):
    if not is_logged_in(connection):
        return

    logger.info("%s is logging out" % connection.user)
    del connection.user
    delattr(connection, "user")


def login_required(method):
    def wrapper(handler, connection, packet):
        if not is_logged_in(connection):
            raise ImError(errcode.LOGIN_REQUIRED)

        packet["sender"] = id(connection.user)
        return method(handler, connection, packet)

    return wrapper
